/*************************************************************************
 * Nuvoton Electronics Corporation confidential
 *
 * Copyright (c) 2008 by Nuvoton Electronics Corporation
 * All rights reserved
 *
 * FILENAME
 *     CY3684_bulkloop.c
 *
 * VERSION
 *     1.0
 *
 * DESCRIPTION
 *     NUC900 USB Host bulk loop back test program
 *
 * HISTORY
 *     2008.06.24       Created
 *
 * REMARK
 *     None
 **************************************************************************/
#ifdef ECOS
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "kapi.h"
#include "diag.h"
#include "wbtypes.h"
#include "wbio.h"
#define printf  diag_printf
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wbio.h"
#include "wblib.h"
#define printf  sysprintf
#endif
#include "nuc900_reg.h"
#include "usb.h"

//#define SYSTEM_CLOCK		18432000
//#define SYSTEM_CLOCK		16670000
//#define SYSTEM_CLOCK		15000000
#define SYSTEM_CLOCK		14318000
#define UART_BAUD_RATE		115200

#ifdef ECOS
#define get_timer_ticks()   cyg_current_time()
#else
#define get_timer_ticks()   sysGetTicks(TIMER0)
#endif


USB_DEV_T  *_ptCY3684Dev = NULL;

volatile INT   _nTestPacketLen;
volatile BOOL  _bIsBulkInCompleted, _bIsBulkOutCompleted;

UINT8  *_u8DataBufferOut, *_u8DataBufferIn;

__align(4096) UINT8  _u8DataBufferOutMem[4096];
__align(4096) UINT8  _u8DataBufferInMem[4096];



static VOID  bulkin_done(URB_T *urb)
{
    //printf("bulkin_done - %d\n", urb->actual_length);

    if (urb->status || (urb->actual_length != _nTestPacketLen)) 
    {
        printf("bulkin_done, urb error:%d, %d\n", urb->status, urb->actual_length);
    }
    else
    {
    	if (strncmp(urb->transfer_buffer, (CHAR *)((UINT32)_u8DataBufferOut), _nTestPacketLen))
    		printf("compare error! %x, %x\n", (INT)urb->transfer_buffer, _u8DataBufferOut);
    }
    _bIsBulkInCompleted = TRUE;
}


static VOID  bulkout_done(URB_T *urb)
{
    //printf("bulkout_done - %d\n", urb->actual_length);

    if (urb->status || (urb->actual_length != _nTestPacketLen))
    {
        printf("bulkout_done, urb error:%d, %d\n", urb->status, urb->actual_length);
    }
    else
    {
	}
     _bIsBulkOutCompleted = TRUE;
}


static VOID *bulkloop_probe(USB_DEV_T *dev, UINT32 ifnum,
                           const USB_DEV_ID_T *id)
{
    if ((dev->descriptor.idVendor != 0x04B4) ||
        (dev->descriptor.idProduct != 0x1004))
    {
    	 printf("bulkloop_probe not his device %04x:%04x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
         return NULL;
    }
             
    printf("bulkloop_probe on usb%d:%d.%d\n", dev->bus->busnum, dev->devnum, ifnum);

    _ptCY3684Dev = dev;
    
    printf("\bulkloop_probe - OK!\n");
    return (VOID *)_ptCY3684Dev;
}


static VOID bulkloop_disconnect(USB_DEV_T *dev, VOID *ptr)
{
}


static USB_DEV_ID_T bulkloop_id_table[] = 
{
    USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT,   /* match_flags */
    0x04B4, 0x1004, 0, 0, 0, 0, 0,
    0,                   /* bInterfaceClass */
    0, 0, 0 
};

USB_DRIVER_T  bulkloop_driver = 
{
    "BULKLOOP",
    bulkloop_probe,
    bulkloop_disconnect,
    {NULL,NULL},                       /* driver_list */ 
    NULL,                              /* *ioctl */
    bulkloop_id_table,
    NULL,                              /* suspend */
    NULL                               /* resume */
};


INT  BulkLoop_Init()
{
    USB_RegisterDriver(&bulkloop_driver);
    return 0;
}



#ifdef ECOS
void TestLoop(cyg_addrword_t data)
#else
void  TestLoop()
#endif
{
    INT    		pipe;
    URB_T		tUrbOut, tUrbIn;
    UINT8		*buff_out, *buff_in;
    UINT32		transfer_count = 0;
    UINT32      test_data;
    INT			t0, t1, nStatus;

	buff_out = (UINT8 *)((UINT32)_u8DataBufferOut);
	buff_in = (UINT8 *)((UINT32)_u8DataBufferIn);
	
	while ((volatile)_ptCY3684Dev == NULL)
	{
#ifndef ECOS	
		Hub_CheckIrqEvent();
#endif		
	}
		
	_nTestPacketLen = 512;
	test_data = 0x8000;
	t0 = t1 = get_timer_ticks();
	while (1)
	{
		if (get_timer_ticks() - t1 > 100)
		{
			int  tmp;

			tmp = (get_timer_ticks() - t0) / 100;
			printf("%02d:%02d:%02d - %d KB (%d)\n", 
					tmp / 3600, (tmp % 3600) / 60, tmp % 60,
					transfer_count/1024, USB_available_memory());
			t1 = get_timer_ticks();
		}

		memcpy(buff_out, (UINT8 *)test_data, _nTestPacketLen);
		test_data += _nTestPacketLen;
		if (test_data > 0x20000)
			test_data = 0x8000;
		
		_bIsBulkOutCompleted = FALSE;		
		memset((UINT8 *)&tUrbOut, 0, sizeof(tUrbOut));
    	pipe = usb_sndbulkpipe(_ptCY3684Dev, 2);
		FILL_BULK_URB(&tUrbOut, _ptCY3684Dev, pipe, buff_out, _nTestPacketLen, bulkout_done, _ptCY3684Dev);
   		nStatus = USB_SubmitUrb(&tUrbOut);
   		if (nStatus < 0)
   		{
   			printf("Submit bulk-out URB error, %d\n", nStatus);
   			break;
   		}

   		while (!_bIsBulkOutCompleted)
   			;
   			
		_bIsBulkInCompleted = FALSE;		
		memset((UINT8 *)&tUrbIn, 0, sizeof(tUrbIn));
    	pipe = usb_rcvbulkpipe(_ptCY3684Dev, 6);
		FILL_BULK_URB(&tUrbIn, _ptCY3684Dev, pipe, buff_in, _nTestPacketLen, bulkin_done, _ptCY3684Dev);
   		nStatus = USB_SubmitUrb(&tUrbIn);
   		if (nStatus < 0)
   		{
   			printf("Submit bulk-int URB error, %d\n", nStatus);
   			break;
   		}

   		while (!_bIsBulkInCompleted)
   			;
   			
   		transfer_count += _nTestPacketLen;
	}
}



#ifdef ECOS
static cyg_handle_t  	thread_handle;
static cyg_thread 		thread;
#define STACKSIZE		8192
static UINT8            _Statck[STACKSIZE];
#endif

int main()
{
#ifndef ECOS 	
    WB_UART_T 	uart;
#endif    
	WB_PLL_T 		sysClock;

	//sysInvalidCache();
	//sysEnableCache(CACHE_WRITE_BACK);
	//sysSetCachePages((UINT32)_u8DataBufferOutMem, 4096, CACHE_DISABLE);
	//sysSetCachePages((UINT32)_u8DataBufferInMem, 4096, CACHE_DISABLE);
	_u8DataBufferOut = (UINT8 *)((UINT32)_u8DataBufferOutMem | 0x80000000);
	_u8DataBufferIn = (UINT8 *)((UINT32)_u8DataBufferInMem | 0x80000000);

	outpw(0xB0000200, (inpw(0xB0000200)|0x200)); //enable USBH clock

	sysClock.pll0 = PLL_200MHZ;				//PLL0 output clock
	sysClock.pll1 = PLL_133MHZ;				//PLL1 output clock
	sysClock.cpu_src = CPU_FROM_PLL0;		//Select CPU clock source
	sysClock.ahb_clk = AHB_CPUCLK_1_2;		//Select AHB clock divider
	sysClock.apb_clk = APB_AHB_1_2;			//Select APB clock divider
	sysSetPLLConfig(&sysClock);				//Call system function call

#ifndef ECOS
	/* initialize UART */
	outpw(REG_MFSEL, inpw(REG_MFSEL) | 0x100);
    uart.uiFreq = SYSTEM_CLOCK;
    uart.uiBaudrate = UART_BAUD_RATE;
    uart.uiDataBits = WB_DATA_BITS_8;
    uart.uiStopBits = WB_STOP_BITS_1;
    uart.uiParity = WB_PARITY_NONE;
    uart.uiRxTriggerLevel = LEVEL_1_BYTE;
    sysInitializeUART(&uart);
	printf("UART initialized\n");

	sysSetTimerReferenceClock (TIMER0, SYSTEM_CLOCK);
	sysStartTimer(TIMER0, 100, PERIODIC_MODE);
#endif

	InitUsbSystem();       
	BulkLoop_Init();

#ifdef ECOS	
 	cyg_thread_create(12, TestLoop, 0, "test",
        				_Statck, STACKSIZE, &thread_handle, &thread);
	cyg_thread_resume(thread_handle);
#else	
	TestLoop();
#endif	

	return 0;
}

#ifndef ECOS
/*
 * standalone.c - minimal bootstrap for C library
 * Copyright (C) 2000 ARM Limited.
 * All rights reserved.
 */

/*
 * RCS $Revision: 1 $
 * Checkin $Date: 08/08/22 9:59p $ 0
 * Revising $Author: Mncheng $
 */

/*
 * This code defines a run-time environment for the C library.
 * Without this, the C startup code will attempt to use semi-hosting
 * calls to get environment information.
 */
 extern unsigned int Image$$ZI$$Limit;

void _sys_exit(int return_code)
{
label:  goto label; /* endless loop */
}

void _ttywrch(int ch)
{
    char tempch = (char)ch;
    (void)tempch;
}



__value_in_regs struct R0_R3 {unsigned heap_base, stack_base, heap_limit, stack_limit;} 
    __user_initial_stackheap(unsigned int R0, unsigned int SP, unsigned int R2, unsigned int SL)
{
    struct R0_R3 config;

    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
    config.stack_base = 0x800000; //Stack base;

/*
To place heap_base directly above the ZI area, use:
    extern unsigned int Image$$ZI$$Limit;
    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
(or &Image$$region_name$$ZI$$Limit for scatterloaded images)

To specify the limits for the heap & stack, use e.g:
    config.heap_limit = SL;
    config.stack_limit = SL;
*/

    return config;
}

/* end of file standalone.c */

/* end of file standalone.c */
#endif

